home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Online / hsc / source / hsctools / hscdepp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-02  |  17.0 KB  |  710 lines

  1. /*
  2.  * This source code is part of hsc, a html-preprocessor,
  3.  * Copyright (C) 1995-1997  Thomas Aglassinger
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20. /*
  21.  * hsctools/hscdepp.c
  22.  *
  23.  * hsc dependency procreator
  24.  *
  25.  * updated: 28-Mar-1997
  26.  * created:  8-Jul-1996
  27.  */
  28.  
  29. /* ANSI includes */
  30. #include <stdio.h>
  31. #include <errno.h>
  32. #include <string.h>
  33. #include <time.h>
  34.  
  35. /* include revision data */
  36. #include "hsctools/depp_rev.h"
  37.  
  38. /* ugly includes */
  39. #include "ugly/ustring.h"
  40. #include "ugly/dllist.h"
  41. #include "ugly/expstr.h"
  42. #include "ugly/infile.h"
  43. #include "ugly/uargs.h"
  44. #include "ugly/prginfo.h"
  45. #include "ugly/returncd.h"
  46.  
  47. /* hsclib includes */
  48. #include "hscprj/document.h"
  49. #include "hscprj/project.h"
  50. #include "hscprj/license.h"
  51.  
  52. #ifdef AMIGA
  53. /* AmigaOS version string
  54.  * (imported from "hscdepp_rev.h")
  55.  */
  56. static const STRPTR AmigaOS_version = VERSTAG;
  57. #endif
  58.  
  59. /* prefix for messages */
  60. #define HD ""
  61. #define DHD "*hscdep* "
  62. #define SHIT "*** "             /* prefix for total failure */
  63.  
  64. /* debugging define */
  65. #ifdef DEBUG
  66. #undef DEBUG
  67. #define DEBUG 1
  68. #endif
  69.  
  70. #ifdef D
  71. #undef D
  72. #endif
  73.  
  74. #if DEBUG
  75. #define D(x) if (debug) {x;}
  76. #else
  77. #define D(x) {/*nufin*/}
  78. #endif
  79.  
  80. /* step-sizes for input-file/depency-string */
  81. #define CHUNKSIZE_INPUTFILE (64*1024)
  82. #define CHUNKSIZE_DEPENDSTR (16*1024)
  83.  
  84. /* default parameters */
  85. #define DEFAULT_PROJECT "hsc.project"   /* project-filename */
  86. #define DEFAULT_NAMEALL "all_hsc"       /* "all"-rule */
  87.  
  88. /* size of buffer for fgets() */
  89. #define MAXBUFSIZE 1024
  90.  
  91. #define STR_DEPENDS_PRECEDE \
  92.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies precede ---\n"
  93. #define STR_DEPENDS_FOLLOW \
  94.     "# --- DO NOT MODIFY THIS LINE -- hsc-dependencies follow ---\n"
  95.  
  96. /*
  97.  * global vars
  98.  */
  99. static int return_code = RC_FAIL;       /* exit code of program */
  100.  
  101. static STRPTR makefile = NULL;
  102. static STRPTR prjfile = NULL;
  103. static STRPTR nameall = NULL;
  104. static BOOL verbose = FALSE;
  105. static BOOL nobackup = FALSE;
  106. static BOOL notaglines = FALSE;
  107. static BOOL debug = FALSE;
  108.  
  109. static EXPSTR *lines_precede = NULL;
  110. static EXPSTR *lines_follow = NULL;
  111. static EXPSTR *lines_depend = NULL;
  112.  
  113. static HSCPRJ *project = NULL;
  114.  
  115. /*
  116.  * cleanup: free all resources
  117.  * (called in any case)
  118.  */
  119. static VOID cleanup(VOID)
  120. {
  121.     D(fprintf(stderr, "(cleanup)\r"));
  122.     del_project(project);
  123.     del_estr(lines_precede);
  124.     del_estr(lines_follow);
  125.     del_estr(lines_depend);
  126.     D(fprintf(stderr, "         "));
  127. }
  128.  
  129. static VOID set_return_code(int new_code)
  130. {
  131.     if (new_code > return_code)
  132.         return_code = new_code;
  133. }
  134.  
  135. /*
  136.  * hsc_nomem_handler
  137.  *
  138.  * called from ugly/umalloc, if malloc() did return NULL
  139.  */
  140. static BOOL hscdepp_nomem_handler(size_t size)
  141. {
  142.     fputs(SHIT "out of memory\n", stderr);
  143.  
  144.     return_code = RC_FAIL;
  145.  
  146.     exit(return_code);
  147.  
  148.     return (FALSE);             /* immediatly abort */
  149. }
  150.  
  151. VOID msg_corrupt_pf(HSCPRJ * hp, STRPTR reason)
  152. {
  153.     fprintf(stderr, "project-file corrupt: %s\n", reason);
  154. }
  155.  
  156. /*
  157.  * args_ok
  158.  *
  159.  * prepare args, check & parse user args, display error and
  160.  * help message if neccessary
  161.  *
  162.  * result: TRUE, if all args ok and no request for HELP or
  163.  *         LICENSE has been detected
  164.  */
  165. static BOOL args_ok(int argc, char *argv[])
  166. {
  167.     struct arglist *hscdepp_args;       /* argument structure */
  168.     BOOL arg_help = FALSE;
  169.     BOOL arg_license = FALSE;
  170.     BOOL ok = FALSE;
  171.  
  172.     /* create arg-table */
  173.     hscdepp_args = prepare_args
  174.         ("HSCDEPP_ARGS",
  175.          "FILE/T", &makefile, "makefile to update",
  176.          "PRJFILE/T/K", &prjfile, "project file",
  177.          "NAMEALL/T/K", &nameall, "name for `all_hsc' rule",
  178.          "VERBOSE/S", &verbose, "verbose output",
  179.          "NOBACKUP/S", &nobackup, "do not backup makefile",
  180.          "NOTAGLINES/S", ¬aglines, "do not write taglines",
  181.          "-DEBUG/S", &debug, "enable debugging output",
  182.          "HELP=?=-h=--help/S", &arg_help, "display this text",
  183.          "LICENSE/S", &arg_license, "display license",
  184.          NULL);
  185.  
  186.     ok = (hscdepp_args != NULL);
  187.  
  188.     /* set & test args */
  189.     if (ok)
  190.     {
  191.         ok = set_args(argc, argv, hscdepp_args);
  192.  
  193.         /* display argument error message */
  194.         if (!ok)
  195.         {
  196.             pargerr();
  197.             set_return_code(RC_ERROR);
  198.         }
  199.         else if (arg_help || arg_license)
  200.         {
  201.             /*
  202.              * display help or license text
  203.              */
  204.             fprintf_prginfo(stderr);
  205.             if (arg_help)
  206.                 fprintf_arghelp(stderr, hscdepp_args);
  207.             else
  208.                 show_license();
  209.             set_return_code(RC_WARN);
  210.             ok = FALSE;
  211.         }
  212.         else
  213.         {
  214.             /* auto-enable verbose in debug-mode */
  215.             if (debug)
  216.                 verbose = TRUE;
  217.  
  218.             /* display copyright in verbose-mode */
  219.             if (verbose)
  220.                 fprintf_prginfo(stderr);
  221.  
  222.             /* set default-parameters if neccessary */
  223.             if (!prjfile)
  224.             {
  225.                 prjfile = DEFAULT_PROJECT;
  226.                 if (verbose)
  227.                     fprintf(stderr, HD "%s: using default project-file\n",
  228.                             prjfile);
  229.             }
  230.             if (!nameall)
  231.             {
  232.                 nameall = DEFAULT_NAMEALL;
  233.  
  234.             }
  235.  
  236.             /* debugging control output */
  237.             D(
  238.                  if (makefile)
  239.                  {
  240.                  fprintf(stderr, DHD "makefile=`%s'\n", makefile);
  241.                  fprintf(stderr, DHD "makefile=DEFAULT\n");
  242.                  fprintf(stderr, DHD "prjfile =`%s'\n", prjfile);
  243.                  fprintf(stderr, DHD "nameall =`%s'\n", nameall);
  244.                  }
  245.             );
  246.         }
  247.  
  248.         /* release mem used by args */
  249.         free_args(hscdepp_args);
  250.     }
  251.     else
  252.     {
  253.         /* only for developer */
  254.         D(fprintf(stderr, SHIT "ArgDef error: %lu\n", prep_error_num));
  255.     }
  256.  
  257. #if 1
  258.     return (ok);
  259. #else
  260.     return (FALSE);             /* for arg-debugging */
  261. #endif
  262. }
  263.  
  264. /*
  265.  * read_makefile
  266.  *
  267.  * scan for fitting makefile, read all it's data into a list
  268.  * of strings, exept those which are between taglines
  269.  */
  270. static BOOL read_makefile(VOID)
  271. {
  272.     STRPTR scanfile[] =
  273.     {"GNUmakefile", "Makefile", "makefile", NULL};
  274.     FILE *file = NULL;
  275.     BOOL ok = FALSE;
  276.  
  277.     lines_precede = init_estr(1024);
  278.     lines_follow = init_estr(1024);
  279.  
  280.     /*
  281.      * open makefile
  282.      */
  283.     errno = 0;
  284.     if (!makefile)
  285.     {
  286.         /* scan for makefile */
  287.         int i = 0;
  288.  
  289.         D(fprintf(stderr, DHD "scanning makefile\n"));
  290.         makefile = scanfile[0];
  291.         while (!file && makefile)
  292.         {
  293.             D(fprintf(stderr, DHD "  try `%s'\n", makefile));
  294.             file = fopen(makefile, "r");
  295.             if (!file)
  296.             {
  297.                 i += 1;
  298.                 makefile = scanfile[i];
  299.             }
  300.         }
  301.  
  302.     }
  303.     else
  304.     {
  305.         /* use makefile specified by user */
  306.         D(fprintf(stderr, DHD "makefile `%s' specified by user\n", makefile));
  307.         file = fopen(makefile, "r");
  308.     }
  309.  
  310.     if (!file)
  311.     {
  312.         if (!makefile)
  313.             makefile = "Makefile";
  314.         fprintf(stderr, HD "%s: creating new makefile\n", makefile);
  315.         ok = TRUE;
  316.     }
  317.     else
  318.     {
  319.         static STRARR buf[MAXBUFSIZE];  /* buffer for fgets() */
  320.         BOOL found = FALSE;     /* flag: tag-line found */
  321.         STRPTR line = NULL;     /* current line read */
  322.  
  323.         /*
  324.          * read Makefile
  325.          */
  326.  
  327.         /* reset error variable */
  328.         errno = 0;
  329.  
  330.         /*
  331.          * read preceding lines
  332.          */
  333.         do
  334.         {
  335.             line = fgets(buf, MAXBUFSIZE, file);
  336.             if (line)
  337.                 if (!strcmp(line, STR_DEPENDS_FOLLOW))
  338.                     found = TRUE;
  339.                 else
  340.                     app_estr(lines_precede, line);
  341.         }
  342.         while (!found && !errno && line);
  343.  
  344.         if (errno)
  345.         {
  346.             fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  347.             set_return_code(RC_ERROR);
  348.         }
  349.         else if (!line)
  350.         {
  351.             /* tag-line not found */
  352.             if (verbose)
  353.                 fprintf(stderr, HD "%s: no starting tag-line; "
  354.                         "appending dependencies\n", makefile);
  355.         }
  356.         else
  357.         {
  358.             /*
  359.              * skip old dependencies
  360.              */
  361.             D(fprintf(stderr, DHD "starting tagline found\n"));
  362.  
  363.             found = FALSE;
  364.             do
  365.             {
  366.                 line = fgets(buf, MAXBUFSIZE, file);
  367.                 if (line)
  368.                     if (!strcmp(line, STR_DEPENDS_PRECEDE))
  369.                         found = TRUE;
  370.             }
  371.             while (!found && !errno && line);
  372.  
  373.             if (errno)
  374.             {
  375.                 fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  376.                 set_return_code(RC_ERROR);
  377.             }
  378.             else if (!line)
  379.             {
  380.                 /* tag-line not found */
  381.                 if (verbose)
  382.                     fprintf(stderr, HD "%s: no ending tag-line; "
  383.                             "appending dependencies\n", makefile);
  384.             }
  385.             else
  386.             {
  387.                 /*
  388.                  * read following lines
  389.                  */
  390.                 D(fprintf(stderr, DHD "ending tagline found\n"));
  391.                 do
  392.                 {
  393.                     line = fgets(buf, MAXBUFSIZE, file);
  394.                     if (line)
  395.                         app_estr(lines_follow, line);
  396.                 }
  397.                 while (!errno && line);
  398.  
  399.                 if (errno)
  400.                 {
  401.                     fprintf(stderr, HD "error reading `%s': %s\n", makefile, strerror(errno));
  402.                     set_return_code(RC_ERROR);
  403.                 }
  404.             }
  405.         }
  406.  
  407.         if (!errno)
  408.         {
  409.             if (verbose)
  410.                 fprintf(stderr, HD "%s: makefile read\n", makefile);
  411.             ok = TRUE;
  412.         }
  413.         /* close makefile */
  414.         fclose(file);
  415.     }
  416.  
  417.     return (ok);
  418. }
  419.  
  420. /*
  421.  * read_project
  422.  *
  423.  * read data from project file
  424.  */
  425. static BOOL read_project(VOID)
  426. {
  427.     BOOL ok = FALSE;
  428.     INFILE *inpf = NULL;
  429.  
  430.     if (verbose)
  431.     {
  432.         fprintf(stderr, HD "%s: reading..\r", prjfile);
  433.         fflush(stderr);
  434.     }
  435.  
  436.     /* assign message-callback for corrupt project-file */
  437.     project->CB_msg_corrupt_pf = msg_corrupt_pf;
  438.  
  439.     /* read project-file */
  440.     errno = 0;
  441.     inpf = infopen(prjfile, CHUNKSIZE_INPUTFILE);
  442.     if (inpf)
  443.     {
  444.         if (hsc_project_read_data(project, inpf))
  445.         {
  446.             if (verbose)
  447.                 fprintf(stderr, HD "%s: project-file read\n", prjfile);
  448.             ok = TRUE;
  449.         }
  450.         infclose(inpf);
  451.     }
  452.  
  453.     if (!ok)
  454.     {
  455.         fprintf(stderr, HD "error reading `%s'", prjfile);
  456.         if (errno)
  457.             fprintf(stderr, HD ": %s", strerror(errno));
  458.         fprintf(stderr, "\n");
  459.     }
  460.  
  461.     return (ok);
  462. }
  463.  
  464. /*
  465.  * update_makefile
  466.  *
  467.  * create dependency-lines from project-info,
  468.  */
  469.  
  470. /* append linefeed to dependency-line */
  471. static VOID depline_applf(ULONG * linelen)
  472. {
  473.     *linelen = 0;
  474.     app_estr(lines_depend, "\n");
  475. }
  476.  
  477. /* append string to dependency-line */
  478. static VOID depline_appstr(STRPTR s, ULONG * linelen)
  479. {
  480. #define LEADING_BLANKS "   "
  481.     size_t slen = strlen(s);
  482.  
  483.     /* check if line would become too long after appending
  484.      * the current word */
  485.     if ((*linelen + slen) >= 75)
  486.     {
  487.         D(fprintf(stderr, DHD "break line after %lu chars to avoid %lu\n",
  488.                   *linelen, *linelen + slen));
  489.  
  490.         app_estr(lines_depend, " \\\n");
  491.         app_estr(lines_depend, LEADING_BLANKS);
  492.         *linelen = strlen(LEADING_BLANKS);
  493.     }
  494.  
  495.     app_estrch(lines_depend, ' ');
  496.     app_estr(lines_depend, s);
  497.     *linelen = *linelen + slen + 1;
  498. }
  499.  
  500. /*
  501.  * update_makefile - main function
  502.  */
  503. static BOOL update_makefile(VOID)
  504. {
  505.     BOOL ok = FALSE;
  506.     ULONG linelen = 0;          /* length of current line */
  507.     DLNODE *docnode = dll_first(project->documents);
  508.     BOOL bak_ok = TRUE;
  509.  
  510.     lines_depend = init_estr(CHUNKSIZE_DEPENDSTR);
  511.  
  512.     /* append tagline */
  513.     if (!notaglines)
  514.     {
  515.         app_estr(lines_depend, STR_DEPENDS_FOLLOW);
  516.     }
  517.  
  518.     /* append some header info */
  519.     if (!notaglines)
  520.     {
  521. #define MAXTIMEBUF 40
  522.         time_t now = time(NULL);
  523.         STRARR timebuf[MAXTIMEBUF];
  524.  
  525.         if (strftime(timebuf, MAXTIMEBUF, "%A %d-%b-%Y %H:%M:%S",
  526.                      localtime(&now)))
  527.         {
  528.             app_estr(lines_depend, "\n# dependencies updated: ");
  529.             app_estr(lines_depend, timebuf);
  530.             app_estr(lines_depend, "\n\n");
  531.         }
  532.     }
  533.  
  534.     /*
  535.      * append all-rule
  536.      */
  537.     app_estr(lines_depend, nameall);
  538.     app_estr(lines_depend, " :");
  539.     linelen = strlen(nameall) + 2;
  540.  
  541.     while (docnode)
  542.     {
  543.         HSCDOC *document = dln_data(docnode);
  544.         depline_appstr(document->docname, &linelen);
  545.  
  546.         docnode = dln_next(docnode);
  547.     }
  548.     app_estr(lines_depend, "\n\n");
  549.  
  550.     /*
  551.      * append document data
  552.      */
  553.     docnode = dll_first(project->documents);
  554.     while (docnode)
  555.     {
  556.         HSCDOC *document = dln_data(docnode);
  557.         DLNODE *incnode = dll_first(document->includes);
  558.  
  559.         D(fprintf(stderr, DHD "document `%s'\n", document->docname));
  560.  
  561.         app_estr(lines_depend, document->docname);
  562.         app_estr(lines_depend, " :");
  563.  
  564.         linelen = strlen(document->docname) + 2;
  565.  
  566.         /* dependency for main source */
  567.         depline_appstr(document->sourcename, &linelen);
  568.  
  569.         /* dependencies for includes */
  570.         while (incnode)
  571.         {
  572.             HSCINC *include = dln_data(incnode);
  573.             depline_appstr(include->name, &linelen);
  574.  
  575.             incnode = dln_next(incnode);
  576.         }
  577.  
  578.         /* append linefeed after dependency-list */
  579.         app_estr(lines_depend, "\n\n");
  580.  
  581.         docnode = dln_next(docnode);
  582.     }
  583.  
  584.     /* append tagline */
  585.     if (!notaglines)
  586.         app_estr(lines_depend, STR_DEPENDS_PRECEDE);
  587.  
  588.     /*
  589.      * create backup
  590.      */
  591.     if (!nobackup)
  592.     {
  593.         EXPSTR *makefile_bak = init_estr(32);   /* filename for backup */
  594.  
  595.         set_estr(makefile_bak, makefile);
  596.         app_estr(makefile_bak, ".bak");
  597.  
  598.         /* remove old backup */
  599.         remove(estr2str(makefile_bak));
  600.  
  601.         /* rename old makefile to backup
  602.          *
  603.          * NOTE: if this fails, this can also be because
  604.          * there wasn't any earlier copy, therefor no
  605.          * error-message is displayed */
  606.         if (!rename(makefile, estr2str(makefile_bak)))
  607.         {
  608.             if (verbose)
  609.                 fprintf(stderr, HD "%s: backup created\n",
  610.                         estr2str(makefile_bak));
  611.         }
  612.  
  613.         del_estr(makefile_bak);
  614.     }
  615.  
  616.     /*
  617.      * write makefile
  618.      */
  619.     if (bak_ok)
  620.     {
  621.         FILE *outf = NULL;
  622.  
  623.         /* open output makefile */
  624.         errno = 0;
  625.         outf = fopen(makefile, "w");
  626.         if (outf)
  627.         {
  628.             /* write output */
  629.             errno = 0;
  630.             fprintf(outf, "%s%s%s",
  631.                     estr2str(lines_precede), estr2str(lines_depend),
  632.                     estr2str(lines_follow));
  633.  
  634.             if (errno)
  635.             {
  636.                 /* write error */
  637.                 fprintf(stderr, "error writing to `%s': %s\n",
  638.                         makefile, strerror(errno));
  639.             }
  640.             else
  641.                 ok = TRUE;
  642.  
  643.             /* close output */
  644.             fclose(outf);
  645.         }
  646.         else
  647.         {
  648.             /* error opening output */
  649.             fprintf(stderr, "error opening `%s' for output: %s\n",
  650.                     makefile, strerror(errno));
  651.         }
  652.     }
  653.  
  654.     return (ok);
  655. }
  656.  
  657. /*
  658.  *
  659.  * main function
  660.  *
  661.  */
  662. int main(int argc, char *argv[])
  663. {
  664. #ifndef BETA
  665. #define BETA 0
  666. #endif
  667.     /* set program information */
  668.     set_prginfo("hscdepp", UGLY_AUTHOR, VERSION, REVISION, BETA,
  669.                 "hsc dependency procreator",
  670.                 "Freeware, type `hscdepp LICENSE' for details.");
  671.  
  672. #if DEBUG
  673.     /* display a memory tracking report */
  674.     /* at end of execution */
  675.     atexit(atexit_uglymemory);
  676. #endif
  677.  
  678.     /* install nomem-handler */
  679.     ugly_nomem_handler = hscdepp_nomem_handler;
  680.  
  681.     /* use cleanup() as additional exit func */
  682.     if (!atexit(cleanup))
  683.     {
  684.         /*
  685.          * main procedure
  686.          */
  687.         return_code = RC_OK;
  688.         project = new_project();
  689.         if (project
  690.             && args_ok(argc, argv)
  691.             && read_makefile()
  692.             && read_project()
  693.             && update_makefile()
  694.         )
  695.         {
  696.             if (verbose)
  697.             {
  698.                 fprintf(stderr, HD "%s: updated using `%s'\n",
  699.                         makefile, prjfile);
  700.             }
  701.             return_code = RC_OK;
  702.         }
  703.     }
  704.     else
  705.     {
  706.         fputs(SHIT "atexit() failed ", stderr);
  707.     }
  708.     return (return_code);
  709. }
  710.